package tool.soft

import java.io.File
import akka.stream.Materializer
import dao._
import implicits.Implicits._
import models.Tables
import models.Tables._
import org.joda.time.DateTime
import play.api.data.FormBinding
import play.api.libs.ws.WSClient
import play.api.mvc.{AnyContent, Request}
import play.twirl.api.Html
import shared.Pojo._
import tool.Pojo._
import tool.plot._
import tool.soft.AllSoft.SoftBT
import tool._

import scala.language.postfixOps
import play.api.i18n.Messages
import utils.Utils
import upickle.default._

/** Created by yz on 15/9/2020
  */
object DiagnoseSoft extends DiagnoseSoftT with SoftBT {

  override def getFileInfos(workspaceDir: File, index: Int)(implicit
      matrixFileDataDao: MatrixFileDataDao,
      messages: Messages
  ): List[FileInfoData] = {
    List(
      FileInfoData("Prediction.csv", messages("prediction")),
      FileInfoData("Prediction_Summary.csv", messages("predictionSummary")),
      FileInfoData("VarImp.csv", messages("varImp")),
      FileInfoData("ROC_Curve.pdf", messages("rOCCurve")),
      FileInfoData("ROC_Curve_Data.csv", messages("rOCCurveData")),
      FileInfoData("PR_Curve.pdf", messages("pRCurve")),
      FileInfoData("PR_Curve_Data.csv", messages("pRCurveData")),
      FileInfoData("Single_Met_ROC.csv", messages("singleMetROC")),
      FileInfoData("Single_Met_ROC.pdf", messages("singleMetROCCurve"))
    )
  }

  override def resultDeal(workspaceDir: File, resultDir: File)(implicit
      ws: WSClient,
      materializer: Materializer
  ): Unit = {
    Tool.resultDeal(workspaceDir, resultDir)
  }

  override def produceConfigFile(workspaceDir: File, index: Int)(implicit
      request: Request[AnyContent],
      formBinding: FormBinding
  ) = {
    Utils.t2ConfigFile(data, Tool.getCalculateConfigJsonFile(workspaceDir))
    Utils.t2ConfigFile(workspaceDir, data)
    plot.Roc.initConfigFile(workspaceDir, "")
    plot.Pr.initConfigFile(workspaceDir, "")
  }

  override def getResultHtml(missionId: Int)(implicit request: Request[AnyContent], messages: Messages): Html = {
    views.html.user.mission.diagnoseResult(missionId)
  }

  def getArg(implicit request: Request[AnyContent], messages: Messages, formBinding: FormBinding): ujson.Value = {
    val methodStr = data.method match {
      case "lr" => "Logistic Regression"
      case "rf" => "Random Forest"
      case "gb" => "Gradient Boosting"
    }
    val groupArg = if (data.group.isBlank) {
      ujson.Obj()
    } else ujson.Obj(messages("group") -> data.group)
    val scaleMethodMap = Tool.getScaleMethodMap
    ujson.Obj(
      messages("scaleMethod") -> scaleMethodMap(data.scaleMethod),
      messages("modelingMethod") -> methodStr
    ) ++ groupArg
  }

  override def getCommandData(workspaceDir: File, resultDir: File, index: Int): List[CommandData] = {
    val solutionFile = new File(Tool.dataDir, "color_solution/color_solution_1.txt")
    val rawDataFile = new File(workspaceDir, "AllMet_Raw.txt")
    val standardFile = Tool.getStandardFile(workspaceDir)
    val data = read[DiagnoseData](Tool.getCalculateConfigJsonFile(workspaceDir))
    val calculateRFileName = data.method match {
      case "lr" => "logistic.R"
      case "rf" => "rf.R"
      case "gb" => "gb.R"
    }
    val command =
      s"""
         |${"Rscript".condaPath()} ${Tool.rPath.unixPath}/standard.R
         |${"Rscript".condaPath()} ${new File(Tool.rPath, calculateRFileName).unixPath} --i ${standardFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Tool.rPath, "roc_calculate.R").unixPath}
         |${"Rscript".condaPath()} ${new File(Tool.rPath, "roc_plot.R").unixPath}
           """.stripMargin
    val plotCommands = List(
      plot.Roc.getCommand(workspaceDir, ""),
      plot.Pr.getCommand(workspaceDir, "")
    )
    List(CommandData(workspaceDir, List(command) ::: plotCommands))
  }

  override def getHtml(missionName: String, missionId: Option[Int])(implicit
      request: Request[AnyContent],
      messages: Messages
  ): Html = {
    views.html.user.soft.diagnose(missionName, missionId)
  }

  override def getMission(implicit
      request: Request[AnyContent],
      matrixFileDataDao: MatrixFileDataDao,
      messages: Messages,
      formBinding: FormBinding
  ): Tables.MissionRow = {
    val initInput = List(data.file, data.groupFile)
    val argJson = getArg
    MissionRow(
      id = 0,
      missionName = s"${data.missionName}",
      kind = nameStr,
      userId = userId,
      startTime = new DateTime(),
      state = "preparing",
      arg = argJson,
      input = initInput
    )
  }

  override def produceInputFile(
      workspaceDir: File
  )(implicit request: Request[AnyContent], dao: MyDao, formBinding: FormBinding): Any = {
    val rawDataFile = new File(workspaceDir, "AllMet_Raw.txt")
    Tool.produceRawMetaboliteFile(userId, data.file, rawDataFile)

    val originalGroupFile = new File(workspaceDir, "original_group.txt")
    Tool.produceRawGroupFile(userId, data.groupFile, rawDataFile, originalGroupFile)
    val groupFile = Tool.getGroupFile(workspaceDir)
    if (data.group.isBlank) {
      groupFile.fileCopyToDir(workspaceDir)
    } else {
      val groupStr = data.group
      val groups = groupStr.mySplit(" vs ")
      originalGroupFile.txtLines.lineSeqMap
        .filter { map =>
          groups.contains(map("ClassNote"))
        }
        .csvLines
        .toTxtFile(groupFile)
    }
  }

  override def data(implicit request: Request[AnyContent], formBinding: FormBinding) = {
    FormTool.diagnoseForm.bindFromRequest().get
  }

}
